﻿using DBUtil.Net.Attributes;
using Common.Net.Accessors;
using Common.Net.Data;
using Common.Net.Extensions;
using Common.Net.Logger;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;

//注意: Insert 中不会出现解析表达式的情况

namespace DBUtil.Net.Builders
{
    /// <summary>
    /// 插入构造器
    /// </summary>
    public class InsertBuilder : BaseBuilder
    {
        protected static readonly ILogger<InsertBuilder> logger = LoggerFactory.CreateLogger<InsertBuilder>();
        public EnumInsertBuilderType Type { get; protected set; }
        /// <summary>
        /// 参与构建sql, 如: insert {TableName}
        /// </summary>
        public string TableName { get; private set; }
        /// <summary>
        /// 可能是 
        /// <list type="bullet">
        /// <item>Dictionary&lt;string,object>: db.Insert("t_user",new {Name="jack",Age=10}.ToDictionary())</item>
        /// <item>IEnumerable&lt;Dictionary&lt;string,object>>: db.Insert("t_user",[new {Name="jack",Age=10}.ToDictionary()])</item>
        /// <item>Entity: db.Insert&lt;PersonEntity>(new PersonEntity()) 或 db.Insert&lt;PersonEntity>().SetEntity(new...)</item>
        /// <item>IEnumerable&lt;Entity>: db.Insert&lt;PersonEntity>([new PersonEntity()]) 或 db.Insert&lt;PersonEntity>().SetEntity([new...])</item>
        /// </list>
        /// </summary>
        public object Object { get; protected set; }
        internal InsertBuilder(DBAccess db, string tableName, object obj) : base(db)
        {
            Type = EnumInsertBuilderType.InsertByDictionary;
            Object = obj;
            TableName = tableName;
        }
        #region batch
        protected int? rowsCountPerBatch = null;
        protected IsolationLevel? batchIsolationLevel = null;
        /// <summary>
        /// 当一次插入的数据太多时,尝试分批执行, 以防db报错
        /// <list type="bullet">
        /// <item>sqlserver: 最大可插入1000行</item>
        /// <item>mysql: 无最大行数限制, 但与server的通讯包有限制(ensure 'max_allowed_packet' is greater than...)</item>
        /// </list>
        /// </summary>
        public virtual InsertBuilder BatchOption(int? rowsCountPerBatch, IsolationLevel? batchIsolationLevel = null)
        {
            if (rowsCountPerBatch < 1) throw new Exception($"rowsCountPerBatch不能小于1!");
            this.rowsCountPerBatch = rowsCountPerBatch;
            this.batchIsolationLevel = batchIsolationLevel;
            return this;
        }
        #endregion
        #region 复写AsTable
        /// <summary>
        /// 更改生成的 Insert 语句中的表名, 如:
        /// <code>
        /// db.Insert("t_person").AsTable("t_person_202401")
        /// </code>
        /// </summary>
        public virtual InsertBuilder AsTable(string newTableName)
        {
            TableName = newTableName;
            return this;
        }
        /// <summary>
        /// 更改生成的 Insert 语句中的表名, 如:
        /// <code>
        /// db.Insert("t_person").AsTableIf(DateTime.Now >= DateTime.Parse("2024-01-01"), "t_person_202401")
        /// </code>
        /// </summary>
        public virtual InsertBuilder AsTableIf(bool condition, string newTableName)
            => condition ? AsTable(newTableName) : this;
        /// <summary>
        /// 更改生成的 Insert 语句中的表名, 如:
        /// <code>
        /// db.Insert("t_person").AsTable(t => t + DateTime.Now.ToString("yyyyMM"))
        /// </code>
        /// </summary>
        public virtual InsertBuilder AsTable(Func<string, string> func)
        {
            var newTableName = func?.Invoke(TableName);
            if (newTableName.IsNotNullOrEmptyOrWhiteSpace()) TableName = newTableName;
            return this;
        }
        /// <summary>
        /// 更改生成的 Insert 语句中的表名, 如:
        /// <code>
        /// db.Insert("t_person").AsTableIf(true, t => t + DateTime.Now.ToString("yyyyMM"))
        /// </code>
        /// </summary>
        public virtual InsertBuilder AsTableIf(bool condition, Func<string, string> func)
            => condition ? AsTable(func) : this;
        #endregion
        #region 复写超时设置
        /// <summary>
        /// 设置sql语句执行超时时间
        /// </summary>
        public override InsertBuilder CommandTimeout(int timeoutSeconds)
            => base.CommandTimeout(timeoutSeconds) as InsertBuilder;
        /// <summary>
        /// 设置sql语句执行超时时间
        /// </summary>
        public override InsertBuilder CommandTimeoutIf(bool condition, int timeoutSeconds)
            => condition ? CommandTimeout(timeoutSeconds) : this;
        #endregion
        #region SetColumn & IgnoreColumns & OnlyColumns
        internal List<SetIgnoreItem> setIgnores = [];
        internal InsertBuilder ReplaceSetIgnores(List<SetIgnoreItem> newSetIgnores)
        {
            setIgnores = newSetIgnores;
            return this;
        }
        private const string NO_EXPRESSION_MESSAGE = $"""不能在 insert 中使用表达式插入, 如果想插入 select 语句的结果, 可参考: insert.SetColumn("age",new RawString(db.Select<Person>().ToSqlCount()))!""";
        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.SetColumn("name","jack")</item>
        /// <item>insert.SetColumn("name",new RawString(db.Select&lt;Person>().ToSqlCount()))</item>
        /// </list>
        /// 注意: 下面是禁止的
        /// <list type="bullet">
        /// <item>不能使用表达式或委托, 如: insert.SetColumn("name",()=>db.Select&lt;Person>().Count())</item>
        /// <item>不能给json列使用RawString, 如: [JsonStore(Bucket="ext", Key="CreateTime")]prop CreateTime; insert.SetColumn("name",new RawString("selct now()"))</item>
        /// </list>
        /// </summary>
        public virtual InsertBuilder SetColumn(string colname, object constantVal)
        {
            if (constantVal is Expression || constantVal is Delegate) throw new Exception(NO_EXPRESSION_MESSAGE);
            SetIgnoreItem.SetColumn(db, setIgnores, colname, constantVal);
            return this;
        }

        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.SetColumnIf(true,"name","jack")</item>
        /// <item>insert.SetColumnIf(1>0,"name",new RawString(db.Select&lt;Person>().ToSqlCount()))</item>
        /// </list>
        /// 注意: 下面是禁止的
        /// <list type="bullet">
        /// <item>不能使用表达式或委托, 如: insert.SetColumnIf(true,"name",()=>db.Select&lt;Person>().Count())</item>
        /// <item>不能给json列使用RawString, 如: [JsonStore(Bucket="ext", Key="CreateTime")]prop CreateTime; insert.SetColumnIf(true,"name",new RawString("selct now()"))</item>
        /// </list>
        /// </summary>
        public virtual InsertBuilder SetColumnIf(bool condition, string colname, object constantVal) => condition ? SetColumn(colname, constantVal) : this;

        /// <summary>
        /// 示例: insert.IgnoreColumns("name","age")
        /// </summary>        
        public virtual InsertBuilder IgnoreColumns(params string[] colNames)
        {
            SetIgnoreItem.IgnoreColumns(db, setIgnores, colNames);
            return this;
        }
        /// <summary>
        /// 示例: insert.IgnoreColumnsIf(true,"name","age")
        /// </summary>
        public virtual InsertBuilder IgnoreColumnsIf(bool condition, params string[] colNames) => condition ? IgnoreColumns(colNames) : this;
        /// <summary>
        /// 示例: insert.OnlyColumns("name","age")
        /// </summary>
        public virtual InsertBuilder OnlyColumns(params string[] colNames)
        {
            SetIgnoreItem.OnlyColumns(db, setIgnores, colNames);
            return this;
        }
        /// <summary>
        /// 示例: insert.OnlyColumnsIf(true,"name","age")
        /// </summary>
        public virtual InsertBuilder OnlyColumnsIf(bool condition, params string[] colNames) => condition ? OnlyColumns(colNames) : this;
        #endregion        
        #region GetInsertedDatas
        /// <summary>
        /// 仅对第一个 setDic 进行过滤, 防止插入行数太多 消耗性能<br/>
        /// 按调用 setignore 方法的顺序执行<br/>
        /// affectAllRowsCols: 给后面插入的时候用(和这里的过滤没关系), SetColumn 指定的值需要影响到插入的所有行(如果有多行的话)
        /// </summary>
        private void ApplyFilter(List<Dictionary<string, object>> setDics, List<string> affectAllRowsCols)
        {
            for (int i = 0; i < setIgnores.Count; i++)
            {
                var setIgnoreItem = setIgnores[i];
                if (setIgnoreItem.Type == EnumSetIgnoreType.SetColumn)
                {
                    setDics[0]
                        .RemoveFluent(setIgnoreItem.ColumnNames[0])
                        .RemoveFluent(setIgnoreItem.ColumnNamesNoQuote[0])
                        .SetFluent(setIgnoreItem.ColumnNames[0], setIgnoreItem.Value);
                    affectAllRowsCols
                        .RemoveFluent(setIgnoreItem.ColumnNames[0])
                        .RemoveFluent(setIgnoreItem.ColumnNamesNoQuote[0])
                        .AddFluent(setIgnoreItem.ColumnNames[0]);
                }
                else if (setIgnoreItem.Type == EnumSetIgnoreType.IgnoreColumn)
                {
                    for (int j = 0; j < setIgnoreItem.ColumnNames.Length; j++)
                    {
                        setDics[0]
                            .RemoveFluent(setIgnoreItem.ColumnNames[j])
                            .RemoveFluent(setIgnoreItem.ColumnNamesNoQuote[j]);
                        affectAllRowsCols
                            .RemoveFluent(setIgnoreItem.ColumnNames[j])
                            .RemoveFluent(setIgnoreItem.ColumnNamesNoQuote[j]);
                    }
                }
                else if (setIgnoreItem.Type == EnumSetIgnoreType.OnlyColumn)
                {
                    var removes = setDics[0].Keys.Where(i => !(setIgnoreItem.ColumnNames.Contains(i) || setIgnoreItem.ColumnNamesNoQuote.Contains(i))).ToList();
                    foreach (var col in removes)
                    {
                        setDics[0].RemoveFluent(col);
                        affectAllRowsCols.RemoveFluent(col);
                    }
                }
            }
        }

        /// <summary>
        /// affectAllRows: 给后面插入的时候用, SetColumn 指定的值需要影响到插入的所有行(如果有多行的话)
        /// </summary>
        private (List<Dictionary<string, object>> setDics, List<string> affectAllRowsCols) GetInsertedDatas()
        {
            List<Dictionary<string, object>> setDics = null;
            if (Object is null) setDics = [[]];
            else if (Object is List<Dictionary<string, object>> _setDics) setDics = _setDics;
            else if (Object is IEnumerable<Dictionary<string, object>> _setDics2) setDics = _setDics2.ToList();
            else if (Object is Dictionary<string, object> _setDics3) setDics = [_setDics3];
            else throw new Exception("初始类型不正确,应该是 Dictionary<string, object> 或 IEnumerable<Dictionary<string, object>>.");

            if (setDics.Count == 0) throw new Exception("没有发现要写入的数据!");
            var affectAllRowsCols = new List<string>(setDics[0].Keys.Count);
            ApplyFilter(setDics, affectAllRowsCols);
            return (setDics, affectAllRowsCols);
        }
        #endregion

        #region 执行
        /// <summary>
        /// 插入并返回自增主键
        /// </summary>
        public virtual TKey ExecuteIdentity<TKey>()
        {
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteIdentity);
            if (sqls.Count > 1)
            {
                return db.RunInTransaction(() =>
                {
                    for (int i = 0; i < sqls.Count - 1; i++)
                    {
                        RunWriteMonitor(new AfterWriteArgument
                        {
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, () => db.ExecuteSql(sqls[i], CommandType.Text, TimeoutSeconds));
                    }
                    return RunWriteMonitor(new AfterWriteArgument
                    {
                        TableName = TableName,
                        WriteType = EnumWriteType.Insert
                    }, () => db.SelectScalar<TKey>(sqls[^1], CommandType.Text, TimeoutSeconds));
                }, batchIsolationLevel);
            }
            else
            {
                return RunWriteMonitor(new AfterWriteArgument
                {
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, () => db.SelectScalar<TKey>(sqls[0], CommandType.Text, TimeoutSeconds));
            }
        }

        /// <summary>
        /// 插入并返回自增主键
        /// </summary>
        public virtual async Task<TKey> ExecuteIdentityAsync<TKey>(CancellationToken cancellationToken = default)
        {
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteIdentity);
            if (sqls.Count > 1)
            {
                return await db.RunInTransactionAsync(async () =>
                {
                    for (int i = 0; i < sqls.Count - 1; i++)
                    {
                        await RunWriteMonitorAsync(new AfterWriteArgument
                        {
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, async () => await db.ExecuteSqlAsync(sqls[i], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                    }
                    return await RunWriteMonitorAsync(new AfterWriteArgument
                    {
                        TableName = TableName,
                        WriteType = EnumWriteType.Insert
                    }, async () => await db.SelectScalarAsync<TKey>(sqls[^1], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                }, batchIsolationLevel);
            }
            else
            {
                return await RunWriteMonitorAsync(new AfterWriteArgument
                {
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, async () => await db.SelectScalarAsync<TKey>(sqls[0], CommandType.Text, TimeoutSeconds, null, cancellationToken));
            }
        }

        /// <summary>
        /// 插入并返回自增主键
        /// </summary>
        public virtual int ExecuteIdentity() => ExecuteIdentity<int>();

        /// <summary>
        /// 插入并返回自增主键
        /// </summary>
        public virtual async Task<int> ExecuteIdentityAsync(CancellationToken cancellationToken = default)
            => await ExecuteIdentityAsync<int>(cancellationToken);

        /// <summary>
        /// 插入并返回自增主键
        /// </summary>
        public virtual long ExecuteIdentityLong() => ExecuteIdentity<long>();

        /// <summary>
        /// 插入并返回自增主键
        /// </summary>
        public virtual async Task<long> ExecuteIdentityLongAsync(CancellationToken cancellationToken = default)
            => await ExecuteIdentityAsync<long>(cancellationToken);

        /// <summary>
        /// 插入并返回受影响的行数
        /// </summary>
        public virtual int ExecuteAffrows()
        {
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteAffrows);
            if (sqls.Count > 1)
            {
                return db.RunInTransaction(() =>
                {
                    var count = 0;
                    for (int i = 0; i < sqls.Count; i++)
                    {
                        count += RunWriteMonitor(new AfterWriteArgument
                        {
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, () => db.ExecuteSql(sqls[i], CommandType.Text, TimeoutSeconds));
                    }
                    return count;
                }, batchIsolationLevel);
            }
            else
            {
                return RunWriteMonitor(new AfterWriteArgument
                {
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, () => db.ExecuteSql(sqls[0], CommandType.Text, TimeoutSeconds));
            }
        }

        /// <summary>
        /// 插入并返回受影响的行数
        /// </summary>
        public virtual async Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
        {
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteAffrows);
            if (sqls.Count > 1)
            {
                return await db.RunInTransactionAsync(async () =>
                {
                    var count = 0;
                    for (int i = 0; i < sqls.Count; i++)
                    {
                        count += await RunWriteMonitorAsync(new AfterWriteArgument
                        {
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, async () => await db.ExecuteSqlAsync(sqls[i], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                    }
                    return count;
                }, batchIsolationLevel);
            }
            else
            {
                return await RunWriteMonitorAsync(new AfterWriteArgument
                {
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, async () => await db.ExecuteSqlAsync(sqls[0], CommandType.Text, TimeoutSeconds, null, cancellationToken));
            }
        }
        #endregion

        /// <summary>
        /// 便于 BulkCopy, 如果设置了 RawString 则会被提前执行, 如:
        /// <code>
        /// db.Insert("t_user").SetColumn("count",new RawString("select 1"))
        /// </code>
        /// 为了便于组装 DataTable 将会首先执行 "select 1"
        /// </summary>
        public virtual DataTable ToDataTable()
        {
            var dt = new DataTable { TableName = TableName };
            var (setDics, affectAllRowsCols) = GetInsertedDatas();
            var keys = setDics[0].Keys.ToList();
            var colType = typeof(object);
            //都需要去掉 quote
            foreach (var col in keys) dt.Columns.Add(db.RemoveQuote(col), colType);
            var affectIndexes = affectAllRowsCols.Select(i => keys.FindIndex(j => j == i)).Where(i => i >= 0).ToList();
            var affectValues = keys.Select(i => (object)null).ToList();
            affectIndexes.ForEach(idx => affectValues[idx] = setDics[0][keys[idx]]);
            for (int i = 0; i < setDics.Count; i++)
            {
                var setDic = setDics[i];
                var row = dt.NewRow();
                dt.Rows.Add(row);
                var colIndex = 0;
                foreach (var col in keys)
                {
                    if (i > 0 && affectIndexes.Contains(colIndex))
                    {
                        //因为仅对第一行应用的 setignore 所以要考虑第一行的 affectAllRows
                        row[db.RemoveQuote(col)] = affectValues[colIndex];
                    }
                    else
                    {
                        row[db.RemoveQuote(col)] = setDic[col];
                    }
                    colIndex++;
                }
            }
            return dt;
        }

        public virtual string ToSql(EnumInsertToSql enumInsertToSql) => ToSql(enumInsertToSql, false).First();
        public virtual string ToSql() => ToSql(EnumInsertToSql.ExecuteAffrows, false).First();
        public virtual List<string> ToSqlMulti(EnumInsertToSql enumInsertToSql) => ToSql(enumInsertToSql, true);
        public virtual List<string> ToSqlMulti() => ToSql(EnumInsertToSql.ExecuteAffrows, true);

        /// <summary>
        /// 返回生成的sql
        /// </summary>
        private List<string> ToSql(EnumInsertToSql enumInsertToSql, bool multi)
        {
            if (enumInsertToSql == EnumInsertToSql.ExecuteInserted) throw new Exception($"{Type}模式无法获取新增的数据!");
            if (TableName.IsNullOrEmptyOrWhiteSpace()) throw new Exception($"必须先指定 TableName, 参照: db.Insert(\"test\") 或 insert.AsTable(...)");
            var (setDics, affectAllRowsCols) = GetInsertedDatas();
            var len = setDics.Count;
            var keys = setDics[0].Keys.ToList();
            var affectIndexes = affectAllRowsCols.Select(i => keys.FindIndex(j => j == i)).Where(i => i >= 0).ToList();
            var affectValues = keys.Select(i => (object)null).ToList();
            affectIndexes.ForEach(idx => affectValues[idx] = setDics[0][keys[idx]]);

            var sbHeader = new StringBuilder();
            sbHeader.Append("insert into ").Append(TableName).Append('(').Append(keys.ToStringSeparated(",")).Append(") values");

            //分批次
            var rowsCountPerBatch = multi == false ? int.MaxValue : (this.rowsCountPerBatch ?? db.InsertRowsMaxCountPerBatch);
            var batchCount = setDics.Count / rowsCountPerBatch + (setDics.Count % rowsCountPerBatch > 0 ? 1 : 0);
            //每一个 sbBatch: (1,'jack'),\r\n(2,'tom');
            var sbBatchs = new StringBuilder[batchCount];
            for (int i = 0; i < sbBatchs.Length; i++) sbBatchs[i] = new StringBuilder();

            for (int r = 0; r < len; r++)//每一行
            {
                //先做 batch 计算
                //假设 len=11 rowsCountPerBatch=5
                //即: 0 1 2 3 4      5 6 7 8 9       10
                //那么 r=6 时,  batchIndex=1; sbBatch 是第二个 batch; 当前batch有 5 行数据(batchInnerCount)
                //那么 r=10 时, batchIndex=2; sbBatch 是第三个 batch; 当前batch有 1 行数据
                var batchIndex = r / rowsCountPerBatch;//第几个batch
                var sbBatch = sbBatchs[batchIndex];//当前所属batch
                //var batchInnerCount = (batchIndex + 1) < sbBatchs.Length ? rowsCountPerBatch : (r % rowsCountPerBatch + 1);
                var isBatchFirstRow = r % rowsCountPerBatch == 0;//是否是batch内第一行
                var isBatchSecondRow = r % rowsCountPerBatch == 1;//是否是batch内第二行
                var isBatchEndRow = r % rowsCountPerBatch == rowsCountPerBatch - 1 || r == len - 1;//是否是batch内最后一行

                if (isBatchSecondRow)
                {
                    sbBatch.Insert(0, "\r\n   ");
                    sbBatch.Append("\r\n   ");
                }
                else if (!isBatchFirstRow)
                {
                    sbBatch.Append("\r\n   ");
                }
                sbBatch.Append(" (");

                var setDic = setDics[r];//当前行字典
                var colIndex = 0;//进行的列
                foreach (var col in keys)
                {
                    //非第一列, 需要加入逗号
                    if (colIndex > 0) sbBatch.Append(',');
                    if (r > 0 && affectIndexes.Contains(colIndex))
                    {
                        //因为仅对第一行应用的 setignore 所以要考虑第一行的 affectAllRows
                        sbBatch.Append(db.ConvertToSqlSeg(affectValues[colIndex]).UnWrap());
                    }
                    else
                    {
                        sbBatch.Append(db.ConvertToSqlSeg(setDic[col]).UnWrap());
                    }
                    colIndex++;
                }
                //行结束
                sbBatch.Append(')');
                if (isBatchEndRow) sbBatch.Append(';');
                else sbBatch.Append(',');
            }

            var sbTail = new StringBuilder();
            if (enumInsertToSql == EnumInsertToSql.ExecuteIdentity)
            {
                sbTail.Append("\r\n").Append($"select {db.GetLastInsertedIdSeg()}{(setDics.Count > 1 ? $"+{setDics.Count - 1}" : "")};");
            }
            //合并 sbRows 到 sbHeader
            if (sbBatchs.Length > 1)
            {
                //分批次
                var sqls = new List<string>(sbBatchs.Length);
                for (var i = 0; i < sbBatchs.Length; i++)
                {
                    var sbBatch = sbBatchs[i];
                    sbBatch.Insert(0, sbHeader);
                    if (i == sbBatchs.Length - 1) sbBatch.Append(sbTail);
                    sqls.Add(sbBatch.ToString());
                    sbBatch.Clear();
                }
                sbHeader.Clear(); sbTail.Clear();
                return sqls;
            }
            else
            {
                sbHeader.Append(sbBatchs[0]);
                sbHeader.Append(sbTail);
                var sql = sbHeader.ToString();
                sbHeader.Clear(); sbTail.Clear(); sbBatchs[0].Clear();
                return [sql];
            }
        }

    }

    /// <summary>
    /// 插入构造器
    /// </summary>
    public class InsertBuilder<T> : InsertBuilder where T : class, new()
    {
        protected static new readonly ILogger<InsertBuilder<T>> logger = LoggerFactory.CreateLogger<InsertBuilder<T>>();
        private EntityInfo EntityInfo { get; set; }
        #region 初始化
        internal InsertBuilder(DBAccess db, params T[] entities) : base(db, db.GetEntityInfoInternal<T>().TableNameSeg, entities)
        {
            EntityInfo = db.GetEntityInfoInternal(typeof(T), false);
            Type = entities.IsNullOrEmpty() ? EnumInsertBuilderType.InsertByDto : EnumInsertBuilderType.InsertByEntity;
        }
        internal InsertBuilder(DBAccess db, IEnumerable<T> entities) : base(db, db.GetEntityInfoInternal<T>().TableNameSeg, entities)
        {
            EntityInfo = db.GetEntityInfoInternal(typeof(T), false);
            Type = entities.IsNullOrEmpty() ? EnumInsertBuilderType.InsertByDto : EnumInsertBuilderType.InsertByEntity;
        }
        /// <summary>
        /// 设置实体, 如:
        /// <code>
        /// db.Insert&lt;PersonEntity>().SetEntity(new PersonEntity{...})
        /// </code>
        /// </summary>
        public InsertBuilder<T> SetEntity(params T[] entities)
        {
            Object = entities;
            Type = entities.IsNullOrEmpty() ? EnumInsertBuilderType.InsertByDto : EnumInsertBuilderType.InsertByEntity;
            return this;
        }
        /// <summary>
        /// 设置实体, 如:
        /// <code>
        /// db.Insert&lt;PersonEntity>().SetEntity([new PersonEntity{...}])
        /// </code>
        /// </summary>
        public InsertBuilder<T> SetEntity(IEnumerable<T> entities)
        {
            Object = entities;
            Type = entities.IsNullOrEmpty() ? EnumInsertBuilderType.InsertByDto : EnumInsertBuilderType.InsertByEntity;
            return this;
        }
        #endregion
        #region 复写 BatchOption
        public override InsertBuilder<T> BatchOption(int? rowsCountPerBatch, IsolationLevel? batchIsolationLevel = null)
            => base.BatchOption(rowsCountPerBatch, batchIsolationLevel) as InsertBuilder<T>;
        #endregion
        #region 复写AsTable
        public override InsertBuilder<T> AsTable(string newTableName)
        {
            base.AsTable(newTableName);
            return this;
        }
        public override InsertBuilder<T> AsTableIf(bool condition, string newTableName)
            => condition ? AsTable(newTableName) : this;
        public override InsertBuilder<T> AsTable(Func<string, string> func)
            => base.AsTable(func) as InsertBuilder<T>;
        public override InsertBuilder<T> AsTableIf(bool condition, Func<string, string> func)
            => base.AsTableIf(condition, func) as InsertBuilder<T>;
        #endregion
        #region 复写超时设置
        public override InsertBuilder<T> CommandTimeout(int timeoutSeconds) => base.CommandTimeout(timeoutSeconds) as InsertBuilder<T>;
        public override InsertBuilder<T> CommandTimeoutIf(bool condition, int timeoutSeconds)
            => condition ? CommandTimeout(timeoutSeconds) : this;
        #endregion

        #region InsertIdentity
        private bool _isInsertIdentity = false;
        /// <summary>
        /// 设置将自增主键当做普通列插入
        /// </summary>
        /// <remarks>
        /// 注: 一般自增主键是不参与插入, 如: 
        /// <code>
        /// [Table("t_person")]
        /// public class PersonEntity
        /// { 
        ///     [PrimaryKey(KeyStrategy = KeyStrategy.Identity)]
        ///     prop int Id;
        ///     prop string Name;
        /// }
        /// 
        /// var insert = db.Insert&lt;PersonEntity>().SetEntity(new PersonEntity{Id=2,Name="jack"});
        /// insert.ToSql();
        /// //输出: insert into t_person(Name) values('jack');
        /// 
        /// insert.InsertIdentity().ToSql();
        /// //输出: insert into t_person(Id,Name) values(2,'jack');
        /// </code>
        /// </remarks>
        public InsertBuilder<T> InsertIdentity() => SwitchInsertIdentity(true);
        /// <summary>
        /// 切换是否插入自增主键, <seealso cref="InsertIdentity"/>
        /// </summary>
        public InsertBuilder<T> SwitchInsertIdentity(bool isEnable)
        {
            _isInsertIdentity = isEnable;
            return this;
        }
        #endregion
        #region SetColumn & IgnoreColumns
        internal new InsertBuilder<T> ReplaceSetIgnores(List<SetIgnoreItem> newSetIgnores) => base.ReplaceSetIgnores(newSetIgnores) as InsertBuilder<T>;
        public override InsertBuilder<T> SetColumn(string colname, object constantVal)
        {
            var col = EntityInfo.EntityPropertyInfos.FirstOrDefault(i => i.ColumnNamePure == db.RemoveQuote(colname));
            if (col?.JsonKey.IsNotNullOrEmptyOrWhiteSpace() == true) throw new Exception($"不能给 json 列赋值 RawString!");
            base.SetColumn(colname, constantVal);
            return this;
        }
        public override InsertBuilder<T> SetColumnIf(bool condition, string colname, object constantVal) => condition ? SetColumn(colname, constantVal) : this;
        public override InsertBuilder<T> IgnoreColumns(params string[] colNames) => base.IgnoreColumns(colNames) as InsertBuilder<T>;
        public override InsertBuilder<T> IgnoreColumnsIf(bool condition, params string[] colNames) => condition ? IgnoreColumns(colNames) : this;
        public override InsertBuilder<T> OnlyColumns(params string[] colNames) => base.OnlyColumns(colNames) as InsertBuilder<T>;
        public override InsertBuilder<T> OnlyColumnsIf(bool condition, params string[] colNames) => condition ? OnlyColumns(colNames) : this;

        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.SetColumnExpr(i=>i.Name, "jack")</item>
        /// <item>insert.SetColumnExpr(i=>new{ i.Name, i.Name2}, "jack")</item>
        /// </list>
        /// 注意: 下面是禁止的
        /// <list type="bullet">
        /// <item>不能使用表达式或委托, 如: insert.SetColumnExpr(i=>i.StudentCount,()=>db.Select&lt;Person>().Count())</item>
        /// <item>不能给json列使用RawString, 如: [JsonStore(Bucket="ext", Key="CreateTime")]prop CreateTime; insert.SetColumnExpr(i=>i.CreateTime,new RawString("selct now()"))</item>
        /// </list>
        /// </summary>
        public virtual InsertBuilder<T> SetColumnExpr(Expression<Func<T, object>> propSelector, object constantVal)
        {
            var names = SetIgnoreItem.GetInitOrReturnPropNames(propSelector);
            if (names.IsNullOrEmpty()) throw new Exception($"格式错误,无法获取指定的列: {propSelector}!");
            if (names.Any(i => i.Count > 1) && constantVal is RawString) throw new Exception($"无法处理类似【SetColumn(i=>i.Ext.Detail.Count, new RawString(db.Select<Person>().ToSqlCount())】的设置, 请避免给 Json 赋值时使用 RawString 格式!");
            SetIgnoreItem.SetColumn(db, setIgnores, EntityInfo, names, constantVal);
            return this;
        }
        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.SetColumnExprIf(true, i=>i.Name, "jack")</item>
        /// <item>insert.SetColumnExprIf(1>0, i=>new{ i.Name, i.Name2}, "jack")</item>
        /// </list>
        /// 注意: 下面是禁止的
        /// <list type="bullet">
        /// <item>不能使用表达式或委托, 如: insert.SetColumnExprIf(true,i=>i.StudentCount,()=>db.Select&lt;Person>().Count())</item>
        /// <item>不能给json列使用RawString, 如: [JsonStore(Bucket="ext", Key="CreateTime")]prop CreateTime; insert.SetColumnExprIf(true,i=>i.CreateTime,new RawString("selct now()"))</item>
        /// </list>
        /// </summary>
        public virtual InsertBuilder<T> SetColumnExprIf(bool condition, Expression<Func<T, object>> propSelector, object constantVal)
            => condition ? SetColumnExpr(propSelector, constantVal) : this;
        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.IgnoreColumnsExpr(i=>i.Name)</item>
        /// <item>insert.IgnoreColumnsExpr(i=>new{ i.Name, i.Name2})</item>
        /// </list>
        /// </summary>
        /// <remarks>
        /// 注意: 下面的形式不支持
        /// <list type="bullet">
        /// <item>insert.IgnoreColumnsExpr(i=>i.Ext.Detail.Name)</item>
        /// </list>
        /// </remarks>
        public virtual InsertBuilder<T> IgnoreColumnsExpr(Expression<Func<T, object>> propSelector)
        {
            SetIgnoreItem.IgnoreColumns(db, setIgnores, EntityInfo, propSelector);
            return this;
        }
        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.IgnoreColumnsExprIf(true, i=>i.Name)</item>
        /// <item>insert.IgnoreColumnsExprIf(1>0, i=>new{ i.Name, i.Name2})</item>
        /// </list>
        /// </summary>
        /// <remarks>
        /// 注意: 下面的形式不支持
        /// <list type="bullet">
        /// <item>insert.IgnoreColumnsExprIf(true,i=>i.Ext.Detail.Name)</item>
        /// </list>
        /// </remarks>
        public virtual InsertBuilder<T> IgnoreColumnsExprIf(bool condition, Expression<Func<T, object>> propSelector)
            => condition ? IgnoreColumnsExpr(propSelector) : this;
        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.OnlyColumnsExpr(i=>i.Name)</item>
        /// <item>insert.OnlyColumnsExpr(i=>new{ i.Name, i.Name2})</item>
        /// </list>
        /// </summary>
        /// <remarks>
        /// 注意: 下面的形式不支持
        /// <list type="bullet">
        /// <item>insert.OnlyColumnsExpr(i=>i.Ext.Detail.Name)</item>
        /// </list>
        /// </remarks>
        public virtual InsertBuilder<T> OnlyColumnsExpr(Expression<Func<T, object>> propSelector)
        {
            SetIgnoreItem.OnlyColumns(db, setIgnores, EntityInfo, propSelector);
            return this;
        }
        /// <summary>
        /// 示例: 
        /// <list type="bullet">
        /// <item>insert.OnlyColumnsExprIf(true, i=>i.Name)</item>
        /// <item>insert.OnlyColumnsExprIf(1>0, i=>new{ i.Name, i.Name2})</item>
        /// </list>
        /// </summary>
        /// <remarks>
        /// 注意: 下面的形式不支持
        /// <list type="bullet">
        /// <item>insert.OnlyColumnsExprIf(i=>i.Ext.Detail.Name)</item>
        /// </list>
        /// </remarks>
        public virtual InsertBuilder<T> OnlyColumnsExprIf(bool condition, Expression<Func<T, object>> propSelector)
            => condition ? OnlyColumnsExpr(propSelector) : this;
        #endregion

        #region 执行
        /// <summary>
        /// 插入并返回实体
        /// </summary>
        public virtual T ExecuteInserted()
        {
            //todo? 插入10条数据,只返回一条? 不考虑这种情况吧
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteInserted);
            if (sqls.Count > 1)
            {
                return db.RunInTransaction(() =>
                {
                    for (int i = 0; i < sqls.Count - 1; i++)
                    {
                        RunWriteMonitor(new AfterWriteArgument
                        {
                            EntityInfo = EntityInfo,
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, () => db.ExecuteSql(sqls[i], CommandType.Text, TimeoutSeconds));
                    }
                    return RunWriteMonitor(new AfterWriteArgument
                    {
                        EntityInfo = EntityInfo,
                        TableName = TableName,
                        WriteType = EnumWriteType.Insert
                    }, () => db.SelectModel<T>(sqls[^1], CommandType.Text, TimeoutSeconds));
                }, batchIsolationLevel);
            }
            else
            {
                return RunWriteMonitor(new AfterWriteArgument
                {
                    EntityInfo = EntityInfo,
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, () => db.SelectModel<T>(sqls[0], CommandType.Text, TimeoutSeconds));
            }
        }

        /// <summary>
        /// 插入并返回实体
        /// </summary>
        public virtual async Task<T> ExecuteInsertedAsync(CancellationToken cancellationToken = default)
        {
            //todo? 插入10条数据,只返回一条? 不考虑这种情况吧
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteInserted);
            if (sqls.Count > 1)
            {
                return await db.RunInTransactionAsync(async () =>
                {
                    for (int i = 0; i < sqls.Count - 1; i++)
                    {
                        await RunWriteMonitorAsync(new AfterWriteArgument
                        {
                            EntityInfo = EntityInfo,
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, async () => await db.ExecuteSqlAsync(sqls[i], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                    }
                    return await RunWriteMonitorAsync(new AfterWriteArgument
                    {
                        EntityInfo = EntityInfo,
                        TableName = TableName,
                        WriteType = EnumWriteType.Insert
                    }, async () => await db.SelectModelAsync<T>(sqls[^1], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                }, batchIsolationLevel);
            }
            else
            {
                return await RunWriteMonitorAsync(new AfterWriteArgument
                {
                    EntityInfo = EntityInfo,
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, async () => await db.SelectModelAsync<T>(sqls[0], CommandType.Text, TimeoutSeconds, null, cancellationToken));
            }
        }

        /// <summary>
        /// 插入并返回实体集合
        /// </summary>
        public virtual List<T> ExecuteInsertedList()
        {
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteInserted);
            if (sqls.Count > 1)
            {
                return db.RunInTransaction(() =>
                {
                    for (int i = 0; i < sqls.Count - 1; i++)
                    {
                        RunWriteMonitor(new AfterWriteArgument
                        {
                            EntityInfo = EntityInfo,
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, () => db.ExecuteSql(sqls[i], CommandType.Text, TimeoutSeconds));
                    }
                    return RunWriteMonitor(new AfterWriteArgument
                    {
                        EntityInfo = EntityInfo,
                        TableName = TableName,
                        WriteType = EnumWriteType.Insert
                    }, () => db.SelectModelList<T>(sqls[^1], CommandType.Text, TimeoutSeconds));
                }, batchIsolationLevel);
            }
            else
            {
                return RunWriteMonitor(new AfterWriteArgument
                {
                    EntityInfo = EntityInfo,
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, () => db.SelectModelList<T>(sqls[0], CommandType.Text, TimeoutSeconds));
            }
        }
        /// <summary>
        /// 插入并返回实体集合
        /// </summary>
        /// <returns></returns>
        public virtual async Task<List<T>> ExecuteInsertedListAsync(CancellationToken cancellationToken = default)
        {
            var sqls = ToSqlMulti(EnumInsertToSql.ExecuteInserted);
            if (sqls.Count > 1)
            {
                return await db.RunInTransactionAsync(async () =>
                {
                    for (int i = 0; i < sqls.Count - 1; i++)
                    {
                        await RunWriteMonitorAsync(new AfterWriteArgument
                        {
                            EntityInfo = EntityInfo,
                            TableName = TableName,
                            WriteType = EnumWriteType.Insert
                        }, async () => await db.ExecuteSqlAsync(sqls[i], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                    }
                    return await RunWriteMonitorAsync(new AfterWriteArgument
                    {
                        EntityInfo = EntityInfo,
                        TableName = TableName,
                        WriteType = EnumWriteType.Insert
                    }, async () => await db.SelectModelListAsync<T>(sqls[^1], CommandType.Text, TimeoutSeconds, null, cancellationToken));
                }, batchIsolationLevel);
            }
            else
            {
                return await RunWriteMonitorAsync(new AfterWriteArgument
                {
                    EntityInfo = EntityInfo,
                    TableName = TableName,
                    WriteType = EnumWriteType.Insert
                }, async () => await db.SelectModelListAsync<T>(sqls[0], CommandType.Text, TimeoutSeconds, null, cancellationToken));
            }
        }
        #endregion

        #region ToDataTable
        /// <summary>
        /// 便于 BulkCopy
        /// </summary>
        public override DataTable ToDataTable()
        {
            if (Type == EnumInsertBuilderType.InsertByDictionary) return base.ToDataTable();
            if (Type == EnumInsertBuilderType.InsertByDto) return ToDataTableByDto();
            if (Type == EnumInsertBuilderType.InsertByEntity) return ToDataTableByEntity();
            throw new Exception($"错误的类型:{Type}!");
        }

        private DataTable ToDataTableByDto()
        {
            var dt = new DataTable { TableName = TableName };

            var allProps = EntityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreInsert).ToList();
            var setList = new List<SetListItem>();//set列

            //进行 setIgnore 过滤
            BuilderHelper.ApplySetIgnore(setList, setIgnores, allProps);

            //先把json列提出来
            var jsonSetList = BuilderHelper.SplitJsonStore(setList);
            var groups = jsonSetList.GroupBy(i => i.PropertyInfo.JsonBucket).ToList();

            //先设置列头
            var colType = typeof(object);
            foreach (var setItem in setList) dt.Columns.Add(setItem.ColumnNameNoQuote, colType);
            foreach (var setItem in groups) dt.Columns.Add(db.RemoveQuote(setItem.Key), colType);

            var row = dt.NewRow();
            dt.Rows.Add(row);
            //就一行
            //先处理非json列
            for (int i = 0; i < setList.Count; i++)
            {
                var setItem = setList[i];
                var col = setItem.ColumnNameNoQuote;
                var val = setItem.Value;
                var enum2String = setItem.PropertyInfo?.IsEnum == true && setItem.PropertyInfo?.IsDbString == true;
                if (enum2String && val?.GetType().IsEnum == true) val = val.ToString();
                row[col] = val;
            }

            //再处理json列
            if (groups.IsNotNullOrEmpty())
            {
                for (int i = 0; i < groups.Count; i++)
                {
                    var g = groups[i];
                    var bucket = db.RemoveQuote(g.Key);
                    var colList = g.ToList();
                    //先将sql执行了
                    foreach (var item in colList)
                    {
                        if (item.FromSet && item.Value is RawString raw)
                        {
                            item.Value = db.SelectScalar<object>(raw.String);
                        }
                    }

                    object val = null;
                    //if (colList.Count == 1 && colList.FirstOrDefault().PropertyInfo.JsonKey.IsNullOrEmpty())
                    if (colList.All(i => i.PropertyInfo.JsonKey.IsNullOrEmpty()))
                    {
                        //独占json列
                        //[JsonStore(Bucket="properties")]prop List<string> Addrs
                        val = BuildJsonNode(colList.Select(i => (i.JsonDepthProps, i.Value)).ToList());
                    }
                    else
                    {
                        //非独占json列
                        //[JsonStore(Bucket="properties",Key="ext")]prop List<string> Addrs
                        var kvs = new JsonObject();
                        //再按照 JsonKey 分组
                        var g2 = colList.GroupBy(i => i.PropertyInfo.JsonKey).ToList();
                        for (int j = 0; j < g2.Count; j++)
                        {
                            var colList2 = g2[j].ToList();
                            var _val = BuildJsonNode(colList2.Select(i => (i.JsonDepthProps, i.Value)).ToList());
                            kvs[g2[j].Key] = _val;
                        }
                        val = kvs;
                    }
                    row[bucket] = val.ToJsonFast(ignoreNull: true);
                }
            }
            return dt;
        }
        private DataTable ToDataTableByEntity()
        {
            var dt = new DataTable { TableName = TableName };

            var allProps = EntityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreInsert).ToList();
            var setList = new List<SetListItem>();//set列
            foreach (var prop in allProps)
                if (!prop.IsPrimaryKey || prop.PrimaryKeyStrategy != KeyStrategy.Identity || _isInsertIdentity)
                    setList.Add(new SetListItem(prop, prop.ColumnNameSeg, prop.ColumnNamePure, null, false));
            var accessor = Accessor.Build<T>();

            //进行 setIgnore 过滤
            BuilderHelper.ApplySetIgnore(setList, setIgnores, allProps);

            //先转换成实体数组
            T[] arr = null;
            if (Object is IEnumerable<T> tmp) arr = tmp.ToArray();
            else if (Object is T tmpT) arr = [tmpT];
            else throw new Exception("InsertByEntity 参数错误!");

            //先把json列提出来
            var jsonSetList = BuilderHelper.SplitJsonStore(setList);
            var groups = jsonSetList.GroupBy(i => i.PropertyInfo.JsonBucket).ToList();

            //先设置列头
            var colType = typeof(object);
            foreach (var setItem in setList) dt.Columns.Add(setItem.ColumnNameNoQuote, colType);
            foreach (var setItem in groups) dt.Columns.Add(db.RemoveQuote(setItem.Key), colType);

            //行数
            var len = arr.Count();
            for (int i = 0; i < len; i++)
            {
                var row = dt.NewRow();
                dt.Rows.Add(row);
            }

            //先处理非json列
            for (int i = 0; i < setList.Count; i++)
            {
                var setItem = setList[i];
                var col = setItem.ColumnNameNoQuote;
                for (int j = 0; j < len; j++)
                {
                    var ent = arr[j];
                    var row = dt.Rows[j];
                    object val = null;
                    if (setItem.FromSet)
                    {
                        //来自外部set
                        val = setItem.Value;
                    }
                    else
                    {
                        //从实体属性读取值
                        val = accessor[ent, setItem.PropertyInfo.PropNamePure];
                    }
                    var enum2String = setItem.PropertyInfo?.IsEnum == true && setItem.PropertyInfo?.IsDbString == true;
                    if (enum2String && val?.GetType().IsEnum == true) val = val.ToString();
                    row[col] = val;
                }
            }

            //再处理json列
            if (groups.IsNotNullOrEmpty())
            {
                for (int i = 0; i < groups.Count; i++)
                {
                    var g = groups[i];
                    var bucket = db.RemoveQuote(g.Key);
                    var colList = g.ToList();
                    //先将sql执行了
                    foreach (var item in colList)
                    {
                        if (item.FromSet && item.Value is RawString raw)
                        {
                            item.Value = db.SelectScalar<object>(raw.String);
                        }
                    }

                    for (int j = 0; j < len; j++)
                    {
                        var ent = arr[j];
                        var row = dt.Rows[j];
                        object val = null;
                        if (colList.All(i => i.PropertyInfo.JsonKey.IsNullOrEmpty()))
                        {
                            //独占json列
                            //[JsonStore(Bucket="properties")]prop List<string> Addrs
                            val = BuildJsonNode(colList.Select(i => (i.JsonDepthProps, i.FromSet ? i.Value : accessor[ent, i.PropertyInfo.PropNamePure])).ToList());
                        }
                        else
                        {
                            //非独占json列
                            //[JsonStore(Bucket="properties",Key="ext")]prop List<string> Addrs
                            var kvs = new JsonObject();
                            //再按照 JsonKey 分组
                            var g2 = colList.GroupBy(i => i.PropertyInfo.JsonKey).ToList();
                            for (int k = 0; k < g2.Count; k++)
                            {
                                var colList2 = g2[k].ToList();
                                var _val = BuildJsonNode(colList2.Select(i => (i.JsonDepthProps, i.FromSet ? i.Value : accessor[ent, i.PropertyInfo.PropNamePure])).ToList());
                                kvs[g2[k].Key] = _val;
                            }
                            val = kvs;
                        }
                        row[bucket] = val.ToJsonFast(ignoreNull: true);
                    }
                }
            }
            return dt;
        }
        #endregion

        #region ToSql
        /// <summary>
        /// 返回生成的sql
        /// </summary>
        public override string ToSql(EnumInsertToSql enumInsertToSql)
        {
            if (Type == EnumInsertBuilderType.InsertByDictionary) return base.ToSql(enumInsertToSql);
            if (Type == EnumInsertBuilderType.InsertByDto) return ToSqlByDto(enumInsertToSql);
            if (Type == EnumInsertBuilderType.InsertByEntity) return ToSqlByEntity(enumInsertToSql, false).First();
            throw new Exception($"错误的类型:{Type}!");
        }
        public override string ToSql() => ToSql(EnumInsertToSql.ExecuteAffrows);
        public override List<string> ToSqlMulti() => ToSqlMulti(EnumInsertToSql.ExecuteAffrows);
        public override List<string> ToSqlMulti(EnumInsertToSql enumInsertToSql)
        {
            if (Type == EnumInsertBuilderType.InsertByDictionary) return [base.ToSql(enumInsertToSql)];
            if (Type == EnumInsertBuilderType.InsertByDto) return [ToSqlByDto(enumInsertToSql)];
            if (Type == EnumInsertBuilderType.InsertByEntity) return ToSqlByEntity(enumInsertToSql, true);
            throw new Exception($"错误的类型:{Type}!");
        }

        private string ToSqlByDto(EnumInsertToSql enumInsertToSql)
        {
            var (primary, primaryMulti) = Validate(enumInsertToSql);
            var allProps = EntityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreInsert).ToList();
            var setList = new List<SetListItem>();//set列

            //进行 setIgnore 过滤
            BuilderHelper.ApplySetIgnore(setList, setIgnores, allProps);

            //先把json列提出来
            var jsonSetList = BuilderHelper.SplitJsonStore(setList);

            //
            var sbHeader = new StringBuilder();
            var sbRow = new StringBuilder();
            sbHeader.Append($"insert into ").Append(TableName).Append('(');
            sbRow.Append(" values(");

            //缓存的所有行主键值 单列主键[seg...]
            var priValue = string.Empty;
            //缓存的所有行主键值 联合主键 [{col1:seg1}...]
            var priMultiValue = new Dictionary<string, string>();
            var index = 0;//进行的列
                          //先处理非json列
            for (int i = 0; i < setList.Count; i++)
            {
                var setItem = setList[i];
                var col = setItem.ColumnName;
                if (index > 0)
                {
                    sbHeader.Append(',');
                    sbRow.Append(',');
                }
                sbHeader.Append(col);

                //c#枚举,db中为 string 需要特殊处理
                var enum2String = setItem.PropertyInfo?.IsEnum == true && setItem.PropertyInfo?.IsDbString == true;
                //来自外部set
                string seg = db.ConvertToSqlSeg(setItem.Value, enum2String).UnWrap();

                sbRow.Append(seg);

                if (enumInsertToSql == EnumInsertToSql.ExecuteInserted && setItem.PropertyInfo != null)
                {
                    if (primary != null && primary.ColumnNameSeg == col) priValue = seg;
                    if (primaryMulti.Count > 1 && primaryMulti.Any(i => i.ColumnNameSeg == col))
                        priMultiValue[col] = seg;
                }
                index++;
            }
            //再处理json列
            if (jsonSetList.IsNotNullOrEmpty())
            {
                var groups = jsonSetList.GroupBy(i => i.PropertyInfo.JsonBucket).ToList();
                for (int i = 0; i < groups.Count; i++)
                {
                    var g = groups[i];
                    var bucket = g.Key;
                    var colList = g.ToList();
                    //不能处理 Json 深度赋值时 RawString
                    foreach (var item in colList)
                    {
                        if (item.FromSet && item.JsonDepthProps.IsNotNullOrEmpty() && item.Value is RawString raw)
                        {
                            throw new Exception($"无法处理类似【SetColumn(i=>i.Ext.Detail.Count, new RawString(db.Select<Person>().ToSqlCount())】的设置, 请避免给 Json 深度赋值时使用 RawString 格式!");
                        }
                    }

                    if (index > 0)
                    {
                        sbHeader.Append(',');
                        sbRow.Append(',');
                    }
                    sbHeader.Append(bucket);

                    object val = null;
                    if (colList.All(i => i.PropertyInfo.JsonKey.IsNullOrEmpty()))
                    {
                        //独占json列
                        //[JsonStore(Bucket="properties")]prop List<string> Addrs
                        val = BuildJsonNode(colList.Select(i => (i.JsonDepthProps, i.Value)).ToList());
                        val = db.ConvertJsonLiteralToSql(val, EnumJsonAcceptAsType.Doc).res;
                    }
                    else
                    {
                        //非独占json列
                        //[JsonStore(Bucket="properties",Key="ext")]prop List<string> Addrs
                        var kvs = new JsonObject();
                        //再按照 JsonKey 分组
                        var g2 = colList.GroupBy(i => i.PropertyInfo.JsonKey).ToList();
                        for (int j = 0; j < g2.Count; j++)
                        {
                            var colList2 = g2[j].ToList();
                            var _val = BuildJsonNode(colList2.Select(i => (i.JsonDepthProps, i.Value)).ToList());
                            kvs[g2[j].Key] = _val;
                        }
                        val = kvs;
                        val = db.ConvertJsonLiteralToSql(val, EnumJsonAcceptAsType.Doc).res;
                    }
                    sbRow.Append(val);
                    index++;
                }
            }
            sbHeader.Append(')');
            sbRow.Append(");");

            var sbTail = new StringBuilder();
            if (enumInsertToSql == EnumInsertToSql.ExecuteIdentity)
            {
                //返回自增的主键值 查询后再处理个数
                if (primary.PrimaryKeyStrategy != KeyStrategy.Identity || (primary.PrimaryKeyStrategy == KeyStrategy.Identity && _isInsertIdentity)) throw new Exception("非自增主键或已声明插入自增列,无法获取自动生成的主键值!");
                sbTail.Append("\r\n").Append($"select {db.GetLastInsertedIdSeg()};");
            }
            else if (enumInsertToSql == EnumInsertToSql.ExecuteInserted)
            {
                //segs: "id `Id`,name `Name`"
                var segs = EntityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreSelect).Select(i => i.SelectFunc(null)).ToStringSeparated(",");

                if (primary.PrimaryKeyStrategy == KeyStrategy.Identity && !_isInsertIdentity)
                {
                    //自动生成的主键
                    sbTail.Append($"\r\nselect {segs} from {TableName} where {primary.ColumnNameSeg}={db.GetLastInsertedIdSeg()};");
                }
                else
                {
                    //普通或插入的自增主键
                    if (priMultiValue.Count > 1)
                    {
                        //联合主键
                        //(id,id2) = (1,2)
                        var keys = priMultiValue.Keys.OrderBy(i => i).ToList();
                        var col = "(" + keys.ToStringSeparated(",") + ")";
                        var vals = "(" + priMultiValue.ToList().OrderBy(i => i.Key).Select(i => i.Value).ToStringSeparated(",") + ")";
                        var filter = $"{col} = {vals}";
                        sbTail.Append($"\r\nselect {segs} from {TableName} where {filter};");
                    }
                    else
                    {
                        //单个主键
                        sbTail.Append($"\r\nselect {segs} from {TableName} where {primary.ColumnNameSeg} = {priValue};");
                    }
                }
            }
            //合并 sbRow 到 sbHeader
            sbHeader.Append(sbRow);
            sbHeader.Append(sbTail);
            var sql = sbHeader.ToString();
            //清空
            sbHeader.Clear(); sbRow.Clear(); sbTail.Clear();
            return sql;
        }

        #region BuildJsonNode/BuildEmptyJsonObject/BuildDeepJsonObject
        /// <summary>
        /// 传入:
        /// <code>
        /// [
        ///     (["Ext","Detail","Name"],"jack"),
        ///     (["Ext","Detail","Id"],10),
        /// ]
        /// </code>
        /// 得到:
        /// <code>
        /// {
        ///     "Ext":{
        ///         "Detail":{
        ///             "Name":"jack",
        ///             "Id":10,
        ///         }
        ///     }
        /// }
        /// </code>
        /// </summary>
        private JsonNode BuildJsonNode(List<(List<string> JsonDepthProps, object Value)> setList)
        {
            JsonNode root = null;
            for (int i = 0; i < setList.Count; i++)
            {
                var set = setList[i];
                if (set.JsonDepthProps.IsNullOrEmpty())
                {
                    root = ToJsonNode(set.Value);
                }
                else
                {
                    BuildDeepJsonObject(set.JsonDepthProps, set.Value, ref root);
                }
            }
            return root;
        }
        /// <summary>
        /// 将常量转为 JsonNode 形式
        /// </summary>
        private JsonNode ToJsonNode(object obj)
        {
            if (obj is null) return null;
            if (obj is JsonNode node) return node;
            var json = obj.ToJsonFast(ignoreNull: true, otherSettings: options =>
            {
                options.TypeInfoResolver = new DefaultJsonTypeInfoResolver
                {
                    Modifiers = { (typeInfo) =>
                    {
                        for (int i = 0; i < typeInfo.Properties.Count; i++)
                        {
                            var property = typeInfo.Properties[i];
                            var prop = property.AttributeProvider as PropertyInfo;
                            if (prop != null) property.Name = prop.Name;
                        }
                    } }
                };
            });
            return JsonNode.Parse(json);
        }

        /// <summary>
        /// 传入:
        /// <code>
        /// ["Ext","Detail","Name"]
        /// </code>
        /// 传出:
        /// <code>
        /// {
        ///     "Ext":{
        ///         "Detail":{}
        ///     }
        /// }
        /// </code>
        /// </summary>
        private JsonObject BuildEmptyJsonObject(List<string> props)
        {
            var obj = new JsonObject();
            var botObj = obj;
            for (int i = 0; i < props.Count - 1; i++)
            {
                botObj[props[i]] = new JsonObject();
                botObj = botObj[props[i]].AsObject();
            }
            return obj;
        }

        /// <summary>
        /// 传入:
        /// <code>
        /// props: ["Ext","Detail","Name"]
        /// constObj: "jack"
        /// root: 参照根节点, 假设为null
        /// </code>
        /// 处理后, root为:
        /// <code>
        /// {
        ///     "Ext":{
        ///         "Detail":{
        ///             "Name":"jack"
        ///         }
        ///     }
        /// }
        /// </code>
        /// </summary>
        private void BuildDeepJsonObject(List<string> props, object constObj, ref JsonNode root)
        {
            root ??= new JsonObject();
            var botObj = root;
            for (int i = 0; i < props.Count; i++)
            {
                if (i == props.Count - 1)
                {
                    botObj[props[i]] = ToJsonNode(constObj);
                }
                else
                {
                    if (!botObj.AsObject().ContainsKey(props[i])) botObj[props[i]] = new JsonObject();
                    botObj = botObj[props[i]].AsObject();
                }
            }
        }
        #endregion

        private List<string> ToSqlByEntity(EnumInsertToSql enumInsertToSql, bool multi)
        {
            var (primary, primaryMulti) = Validate(enumInsertToSql);
            var allProps = EntityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreInsert).ToList();
            var setList = new List<SetListItem>();//set列
            foreach (var prop in allProps)
                if (!prop.IsPrimaryKey || prop.PrimaryKeyStrategy != KeyStrategy.Identity || _isInsertIdentity)
                    setList.Add(new SetListItem(prop, prop.ColumnNameSeg, prop.ColumnNamePure, null, false));
            var accessor = Accessor.Build<T>();

            //进行 setIgnore 过滤
            BuilderHelper.ApplySetIgnore(setList, setIgnores, allProps);

            //先转换成实体数组
            T[] arr = null;
            if (Object is IEnumerable<T> tmp) arr = tmp.ToArray();
            else if (Object is T tmpT) arr = [tmpT];
            else throw new Exception("InsertByEntity 参数错误!");
            if (arr.Length == 0) throw new Exception($"InsertByEntity 要求指定至少一行数据!");

            //先把json列提出来
            var jsonSetList = BuilderHelper.SplitJsonStore(setList);
            var groups = jsonSetList.GroupBy(i => i.PropertyInfo.JsonBucket).ToList();

            //行数
            var len = arr.Length;
            //insert into test(id,name)
            var sbHeader = new StringBuilder();
            //分批次
            var rowsCountPerBatch = multi == false ? int.MaxValue : (this.rowsCountPerBatch ?? db.InsertRowsMaxCountPerBatch);
            var batchCount = len / rowsCountPerBatch + (len % rowsCountPerBatch > 0 ? 1 : 0);
            //每一个 sbBatch: (1,'jack'),\r\n(2,'tom');
            var sbBatchs = new StringBuilder[batchCount];
            for (int i = 0; i < sbBatchs.Length; i++) sbBatchs[i] = new StringBuilder();

            sbHeader.Append($"insert into ").Append(TableName).Append('(');
            //缓存的所有行主键值 单列主键[seg...]
            var priValue = new List<string>();
            //缓存的所有行主键值 联合主键 [{col1:seg1}...]
            var priMultiValue = new Dictionary<string, object>[len];
            for (int i = 0; i < len; i++) priMultiValue[i] = [];

            for (int r = 0; r < len; r++)//每一行
            {
                //先做 batch 计算
                //假设 len=11 rowsCountPerBatch=5
                //即: 0 1 2 3 4      5 6 7 8 9       10
                //那么 r=6 时,  batchIndex=1; sbBatch 是第二个 batch; 当前batch有 5 行数据(batchInnerCount)
                //那么 r=10 时, batchIndex=2; sbBatch 是第三个 batch; 当前batch有 1 行数据
                var batchIndex = r / rowsCountPerBatch;//第几个batch
                var sbBatch = sbBatchs[batchIndex];//当前所属batch
                var batchInnerCount = (batchIndex + 1) < sbBatchs.Length ? rowsCountPerBatch : (r % rowsCountPerBatch + 1);
                var isBatchFirstRow = r % rowsCountPerBatch == 0;//是否是batch内第一行
                var isBatchSecondRow = r % rowsCountPerBatch == 1;//是否是batch内第二行
                var isBatchEndRow = r % rowsCountPerBatch == rowsCountPerBatch - 1 || r == len - 1;//是否是batch内最后一行

                if (isBatchSecondRow)
                {
                    sbBatch.Insert(0, "\r\n   ");
                    sbBatch.Append("\r\n   ");
                }
                else if (!isBatchFirstRow)
                {
                    sbBatch.Append("\r\n   ");
                }
                sbBatch.Append(" (");

                var ent = arr[r];//当前行实体
                var index = 0;//进行的列
                //先处理非json列
                for (int i = 0; i < setList.Count; i++)
                {
                    var setItem = setList[i];
                    var col = setItem.ColumnName;
                    if (r == 0)
                    {
                        //仅第一行需要处理header
                        if (index > 0) sbHeader.Append(',');
                        sbHeader.Append(col);
                    }

                    //非第一列, 需要加入逗号
                    if (index > 0) sbBatch.Append(',');

                    string seg = null;
                    //c#枚举,db中为 string 需要特殊处理
                    var enum2String = setItem.PropertyInfo?.IsEnum == true && setItem.PropertyInfo?.IsDbString == true;
                    //其他
                    if (setItem.FromSet)
                    {
                        //来自外部set
                        seg = db.ConvertToSqlSeg(setItem.Value, enum2String).UnWrap();
                    }
                    else
                    {
                        //从实体属性读取值
                        seg = db.ConvertToSqlSeg(accessor[ent, setItem.PropertyInfo.PropNamePure], enum2String).UnWrap();
                    }
                    sbBatch.Append(seg);

                    //处理主键
                    if (enumInsertToSql == EnumInsertToSql.ExecuteInserted && setItem.PropertyInfo != null)
                    {
                        if (primary != null && primary.ColumnNameSeg == col) priValue.Add(seg);
                        if (primaryMulti.Count > 1 && primaryMulti.Any(i => i.ColumnNameSeg == col))
                            priMultiValue[r][col] = seg;
                    }
                    index++;
                }
                //再处理json列
                if (jsonSetList.IsNotNullOrEmpty())
                {
                    for (int i = 0; i < groups.Count; i++)
                    {
                        var g = groups[i];
                        var bucket = g.Key;
                        var colList = g.ToList();
                        if (r == 0)
                        {
                            //第一行校验: 不能处理 Json 深度赋值时 RawString
                            foreach (var item in colList)
                            {
                                if (item.FromSet && item.JsonDepthProps.IsNotNullOrEmpty() && item.Value is RawString raw)
                                {
                                    throw new Exception($"无法处理类似【SetColumn(i=>i.Ext.Detail.Count, new RawString(db.Select<Person>().ToSqlCount())】的设置, 请避免给 Json 深度赋值时使用 RawString 格式!");
                                }
                            }
                        }

                        if (r == 0)
                        {
                            //仅第一行需要处理header
                            if (index > 0) sbHeader.Append(',');
                            sbHeader.Append(bucket);
                        }

                        //构建 jsonDoc
                        JsonNode jsonDoc = null;
                        if (colList.All(i => i.PropertyInfo.JsonKey.IsNullOrEmpty()))
                        {
                            //独占json列
                            //[JsonStore(Bucket="properties")]prop List<string> Addrs
                            //直接合并成 JsonNode
                            jsonDoc = BuildJsonNode(colList.Select(i => (i.JsonDepthProps, i.FromSet ? i.Value : accessor[ent, i.PropertyInfo.PropNamePure])).ToList());
                        }
                        else
                        {
                            //非独占json列
                            //[JsonStore(Bucket="properties",Key="ext")]prop List<string> Addrs
                            jsonDoc = new JsonObject();
                            //再按照 JsonKey 分组
                            var g2 = colList.GroupBy(i => i.PropertyInfo.JsonKey).ToList();
                            for (int k = 0; k < g2.Count; k++)
                            {
                                var colList2 = g2[k].ToList();
                                var _val = BuildJsonNode(colList2.Select(i => (i.JsonDepthProps, i.FromSet ? i.Value : accessor[ent, i.PropertyInfo.PropNamePure])).ToList());
                                jsonDoc[g2[k].Key] = _val;
                            }
                        }
                        var jsonDocSqlSeg = db.ConvertJsonLiteralToSql(jsonDoc, EnumJsonAcceptAsType.Doc).res;
                        //非第一列, 需要加入逗号
                        if (index > 0) sbBatch.Append(',');
                        sbBatch.Append(jsonDocSqlSeg);
                        index++;
                    }
                }

                //行结束
                sbBatch.Append(')');
                if (r == 0) sbHeader.Append(')');

                if (isBatchEndRow) sbBatch.Append(';');
                else sbBatch.Append(',');
            }

            var sbTail = new StringBuilder();
            if (enumInsertToSql == EnumInsertToSql.ExecuteIdentity)
            {
                //返回自增的主键值 查询后再处理个数
                if (primary.PrimaryKeyStrategy != KeyStrategy.Identity || (primary.PrimaryKeyStrategy == KeyStrategy.Identity && _isInsertIdentity)) throw new Exception("非自增主键或已声明插入自增列,无法获取自动生成的主键值!");
                sbTail.Append("\r\n").Append($"select {db.GetLastInsertedIdSeg(len)};");
            }
            else if (enumInsertToSql == EnumInsertToSql.ExecuteInserted)
            {
                //segs: "id `Id`,name `Name`"
                var segs = EntityInfo.EntityPropertyInfos.Where(i => i.IsColumn && !i.IsIgnoreSelect).Select(i => i.SelectFunc(null)).ToStringSeparated(",");

                if (primary.PrimaryKeyStrategy == KeyStrategy.Identity && !_isInsertIdentity)
                {
                    //自动生成的主键
                    if (len > 1)
                    {
                        sbTail.Append($"\r\nselect {segs} from {TableName} where {primary.ColumnNameSeg}>={db.GetLastInsertedIdSeg()} order by {primary.ColumnNameSeg} limit {len};");
                    }
                    else
                    {
                        sbTail.Append($"\r\nselect {segs} from {TableName} where {primary.ColumnNameSeg}={db.GetLastInsertedIdSeg()};");
                    }
                }
                else
                {
                    //普通或插入的自增主键
                    if (priMultiValue.FirstOrDefault().Count > 1)
                    {
                        //联合主键
                        //(id,id2) in ((1,2),(1,3))
                        var keys = priMultiValue.FirstOrDefault().Keys.OrderBy(i => i).ToList();
                        var col = "(" + keys.ToStringSeparated(",") + ")";
                        var vals = priMultiValue.Select(i =>
                         {
                             //return (1,2)
                             return "(" + i.ToList().OrderBy(i => i.Key).Select(i => i.Value).ToStringSeparated(",") + ")";
                         }).ToStringSeparated(",");
                        var filter = $"{col} in ({vals})";
                        sbTail.Append($"\r\nselect {segs} from {TableName} where {filter};");
                    }
                    else
                    {
                        //单个主键
                        if (len > 1)
                        {
                            sbTail.Append($"\r\nselect {segs} from {TableName} where {primary.ColumnNameSeg} in ({priValue.ToStringSeparated(",")});");
                        }
                        else
                        {
                            sbTail.Append($"\r\nselect {segs} from {TableName} where {primary.ColumnNameSeg} = {priValue.First()};");
                        }
                    }
                }
            }
            //合并 sbRows 到 sbHeader
            if (sbBatchs.Length > 1)
            {
                //分批次
                var sqls = new List<string>(sbBatchs.Length);
                for (var i = 0; i < sbBatchs.Length; i++)
                {
                    var sbBatch = sbBatchs[i];
                    sbBatch.Insert(0, " values").Insert(0, sbHeader);
                    if (i == sbBatchs.Length - 1) sbBatch.Append(sbTail);
                    sqls.Add(sbBatch.ToString());
                    sbBatch.Clear();
                }
                sbHeader.Clear(); sbTail.Clear();
                return sqls;
            }
            else
            {
                sbHeader.Append(" values");
                sbHeader.Append(sbBatchs[0]);
                sbHeader.Append(sbTail);
                var sql = sbHeader.ToString();
                sbHeader.Clear(); sbTail.Clear(); sbBatchs[0].Clear();
                return [sql];
            }
        }

        /// <summary>
        /// 基础校验
        /// </summary>
        private (EntityPropertyInfo primary, List<EntityPropertyInfo> primaryMulti) Validate(EnumInsertToSql enumInsertToSql)
        {
            var primary = EntityInfo.PrimaryKeyColumn;
            var primaryMulti = EntityInfo.EntityPropertyInfos.Where(i => i.IsPrimaryKey && i.IsColumn).OrderBy(i => i.Order).ToList();
            //基础校验
            if (primary == null && enumInsertToSql == EnumInsertToSql.ExecuteIdentity)
                throw new Exception($"当前Entity({EntityInfo.TypeClassFullName})未定义主键,无法获取插入后的自增主键值!");
            if (primaryMulti.Count > 1 && enumInsertToSql == EnumInsertToSql.ExecuteIdentity)
                throw new Exception($"当前Entity({EntityInfo.TypeClassFullName})使用联合主键({primaryMulti.Select(i => i.ColumnNameSeg).ToStringSeparated(",")}),无法获取插入后的自增主键值!");
            if (primary == null && (enumInsertToSql == EnumInsertToSql.ExecuteInserted))
                throw new Exception($"当前Entity({EntityInfo.TypeClassFullName})未定义主键,无法查询插入后的数据!");
            return (primary, primaryMulti);
        }
        #endregion
    }

    public class InsertFromSelectBuilder<T> : BaseBuilder where T : class, new()
    {
        private readonly SelectBuilderBase selectBuilder;
        private readonly LambdaExpression expression;
        private readonly string[] propNames;
        private EntityInfo EntityInfo { get; set; }

        internal InsertFromSelectBuilder(DBAccess db, SelectBuilderBase selectBuilder, LambdaExpression expression, string[] propNames) : base(db)
        {
            this.EntityInfo = db.GetEntityInfoInternal<T>();
            this.selectBuilder = selectBuilder;
            this.expression = expression;
            this.propNames = propNames;
            this.TableName = this.EntityInfo.TableNameSeg;
        }
        public string TableName { get; private set; }
        #region 复写AsTable
        public InsertFromSelectBuilder<T> AsTable(string newTableName)
        {
            TableName = newTableName;
            return this;
        }
        public InsertFromSelectBuilder<T> AsTableIf(bool condition, string newTableName)
            => condition ? AsTable(newTableName) : this;
        public InsertFromSelectBuilder<T> AsTable(Func<string, string> func)
        {
            var newTableName = func?.Invoke(TableName);
            if (newTableName.IsNotNullOrEmptyOrWhiteSpace()) TableName = newTableName;
            return this;
        }
        public InsertFromSelectBuilder<T> AsTableIf(bool condition, Func<string, string> func)
            => AsTableIf(condition, func);
        #endregion
        #region 复写超时设置
        public override InsertFromSelectBuilder<T> CommandTimeout(int timeoutSeconds) => base.CommandTimeout(timeoutSeconds) as InsertFromSelectBuilder<T>;
        public override InsertFromSelectBuilder<T> CommandTimeoutIf(bool condition, int timeoutSeconds)
            => condition ? CommandTimeout(timeoutSeconds) : this;
        #endregion

        #region ToSql & 执行
        public string ToSql()
        {
            var selectSql = selectBuilder.ToSqlList(expression);
            var props = propNames.Select(prop => this.EntityInfo.EntityPropertyInfos.First(i => i.PropNamePure == prop)).ToList();
            var jsonProps = props.Where(i => i.JsonBucket.IsNotNullOrEmptyOrWhiteSpace()).ToList();
            if (!jsonProps.Any())
            {
                var cols = props.Select(prop => prop.ColumnNameSeg).ToStringSeparated(",");
                var _sql = $"insert into {TableName}({cols}) {selectSql}";
                return _sql;
            }
            //有json列
            //先处理非json列
            var sb = new StringBuilder();
            var sb2 = new StringBuilder();
            sb.Append($"insert into {TableName}(");
            sb2.Append($"select ");
            props = props.Where(i => i.JsonBucket.IsNullOrEmptyOrWhiteSpace()).ToList();
            var hasNormalCol = props.Any();
            sb.Append(props.Select(i => i.ColumnNameSeg).ToStringSeparated(","));
            sb2.Append(props.Select(i => $"t.{i.PropNameSeg}").ToStringSeparated(","));
            if (hasNormalCol)
            {
                sb.Append(hasNormalCol ? "," : "");
                sb2.Append(hasNormalCol ? "," : "");
            }

            var groups = jsonProps.GroupBy(i => i.JsonBucket).ToList();

            for (int i = 0; i < groups.Count; i++)
            {
                var g = groups[i];
                var bucket = g.Key;
                if (i > 0)
                {
                    sb.Append(',');
                    sb2.Append(',');
                }
                sb.Append(bucket);
                var li = g.ToList();
                if (li.Count == 1 && li[0].JsonKey.IsNullOrEmptyOrWhiteSpace())
                {
                    //独占
                    sb2.Append($"t.{li[0].PropNameSeg}");
                }
                else
                {
                    //非独占
                    //json_object(key1,val,key2,val2)
                    var eles = li.Select(i => $"{db.ProtectString(i.JsonKey)},t.{i.PropNameSeg}").ToStringSeparated(",");
                    sb2.Append($"json_object({eles})");
                }
            }
            sb2.Append(" from (\r\n").Append(selectSql.TrimEnd(';')).Append("\r\n) t");
            sb.Append(')');
            sb.Append(sb2);
            var sql = sb.ToString();
            sb.Clear(); sb2.Clear();
            return sql;
        }

        /// <summary>
        /// 插入并返回受影响的行数
        /// </summary>
        public virtual int ExecuteAffrows()
        {
            var sql = ToSql();
            return RunWriteMonitor(new AfterWriteArgument
            {
                EntityInfo = EntityInfo,
                TableName = TableName,
                WriteType = EnumWriteType.InsertFromSelect
            }, () => db.ExecuteSql(sql, CommandType.Text, TimeoutSeconds));
        }

        /// <summary>
        /// 插入并返回受影响的行数
        /// </summary>
        public virtual async Task<int> ExecuteAffrowsAsync(CancellationToken cancellationToken = default)
        {
            var sql = ToSql();
            return await RunWriteMonitorAsync(new AfterWriteArgument
            {
                TableName = TableName,
                WriteType = EnumWriteType.InsertFromSelect
            }, async () => await db.ExecuteSqlAsync(sql, CommandType.Text, TimeoutSeconds, null, cancellationToken));
        }
        #endregion
    }
}